<template>
  <div class="synonym-tab">
    <TabScaffold :current="pagination.current" :pageSize="pagination.pageSize" :total="total"
      :pageCount="pageData.length" :checkAll="checkAll" @update:current="(v) => pagination.current = v"
      @update:pageSize="(v) => pagination.pageSize = v" @check-all="onCheckAll">
      <!-- 工具栏：左侧 -->
      <template #toolbar-left>
        <a-space>
          <a-button @click="onAdd">新增</a-button>
          <a-button :disabled="!selectedRowKeys.length" @click="onBatchDelete">批量删除</a-button>
          <a-button @click="onImport">导入</a-button>
          <a-button :loading="exporting" @click="onOpenExport">导出</a-button>
        </a-space>
      </template>

      <!-- 工具栏：右侧 -->
      <template #toolbar-right>
        <a-input-search v-model:value="keyword" placeholder="输入搜索" enter-button="搜索" allow-clear @search="onSearch"
          style="width:260px" />
      </template>

      <!-- 表格 -->
      <a-table :columns="columns" :data-source="pageData" row-key="id" :pagination="false" :row-selection="rowSelection"
        :loading="loading" bordered class="table" @change="onTableChange" :customRow="onCustomRow">
        <template #bodyCell="{ column, record }">
          <!-- 名称列 -->
          <template v-if="column.key === 'name'">
            <span class="name-text">{{ record.name }}</span>
          </template>

          <!-- 状态列 -->
          <template v-else-if="column.key === 'status'">
            <span :class="['status', record.status === 'enabled' ? 'on' : 'off']">
              {{ record.status === 'enabled' ? '启用' : '停用' }}
            </span>
          </template>

          <!-- 操作列（保持不变） -->
          <template v-else-if="column.key === 'actions'">
            <span class="ops">
              <a @click="onEdit(record)">编辑</a>
              <span class="sep">|</span>
              <a @click="onDelete(record)" style="color: #ff4d4f;">删除</a>
              <span class="sep">|</span>
              <a v-if="record.status === 'enabled'" @click="onToggleStatus(record, 'disable')">停用</a>
              <span v-else class="disabled">停用</span>
              <span class="sep">|</span>
              <a v-if="record.status === 'disabled'" @click="onToggleStatus(record, 'enable')">启用</a>
              <span v-else class="disabled">启用</span>
            </span>
          </template>
        </template>
      </a-table>
    </TabScaffold>

    <!-- 导入弹窗 -->
    <ImportModal v-model:modelValue="importVisible" title="同义词导入" @import="doImport" />

    <!-- 导出弹窗 -->
    <ExportModal v-model:modelValue="exportVisible" v-model:format="exportFormat" :loading="exporting" title="同义词导出"
      @confirm="onConfirmExport" />
  </div>
</template>

<script lang="ts" setup>
import { computed, reactive, ref, onMounted, watch } from 'vue'
import { useRouter } from 'vue-router'
import { message, Modal } from 'ant-design-vue'
import type { Key } from 'ant-design-vue/es/table/interface'
import type { TableRowSelection } from 'ant-design-vue'
import {
  getSynonymList,
  enableSynonym,
  disableSynonym,
  deleteSynonym,
  deleteSynonyms,
  importSynonymsFile,
  exportSynonyms,
} from '@/api/modules/synonym.api'

import TabScaffold from '@/components/TabScaffold.vue'
import ImportModal from '@/components/ImportModal.vue'
import ExportModal from '@/components/ExportModal.vue'

const router = useRouter()
const TAB_KEY = 'synonym'
const ROUTE_INFO = '/synonymFormInfo'
const ROUTE_FORM = '/synonymFormAdd'
const currentUserCname: string = (window as any).__MicroAPP__?._user?.userInfo?.cname ?? ''

type Row = {
  id: string | number
  name: string
  owner: string
  publishTime: string
  status: 'enabled' | 'disabled'
}

/** ====== 列表数据 ====== */
const pageData = ref<Row[]>([])
const total = ref(0)
const loading = ref(false)

/** 查询 / 分页 / 排序 */
const keyword = ref('')
const pagination = reactive({ current: 1, pageSize: 10 })
const sortState = reactive<{ field: '' | 'publishTime'; order: 'ascend' | 'descend' | null }>({
  field: '',
  order: null,
})

/** 时间格式化：YYYY-MM-DD HH:mm:ss */
function formatDateTime(input?: string) {
  if (!input) return ''
  const d = new Date(input)
  if (isNaN(d.getTime())) return input
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
}

/** 倒序 */
function buildSortParam(): string[] {
  if (!sortState.field || !sortState.order) return ['-date_created']
  const prefix = sortState.order === 'descend' ? '-' : ''
  return [`${prefix}date_created`]
}

async function fetchList() {
  loading.value = true
  try {
    const { list, total: t } = await getSynonymList({
      page: pagination.current,
      pageSize: pagination.pageSize,
      keyword: keyword.value,
      sort: buildSortParam(),
      excludeStatus: 'archived',
    })

    if ((list?.length ?? 0) === 0 && pagination.current > 1) {
      pagination.current = pagination.current - 1
      return
    }

    pageData.value = (list || []).map((it: any) => ({
      id: it.id,
      name: it.querys || '',
      owner: currentUserCname,
      publishTime: formatDateTime(it.date_created),
      status: it.status === 'published' ? 'enabled' : 'disabled',
    }))
    total.value = t || 0
    selectedRowKeys.value = []
  } finally {
    loading.value = false
  }
}

/** 搜索按钮 */
function onSearch() {
  pagination.current = 1
  fetchList()
}

/** 搜索框置空时自动拉取 */
const keywordWasEmpty = ref(true)
watch(
  () => keyword.value,
  (val) => {
    const isEmpty = !val || !val.trim()
    if (isEmpty && !keywordWasEmpty.value) {
      pagination.current = 1
      fetchList()
    }
    keywordWasEmpty.value = isEmpty
  }
)

/** 表格排序变化 */
function onTableChange(_: any, __: any, sorter: any) {
  const s = Array.isArray(sorter) ? sorter[0] : sorter
  const field = (s?.columnKey ?? s?.field ?? '') as 'publishTime' | ''
  const order = (s?.order ?? null) as 'ascend' | 'descend' | null
  if (field === 'publishTime' || order === null) {
    sortState.field = field
    sortState.order = order
    pagination.current = 1
    fetchList()
  }
}

/** 首次进入、分页变化时拉取 */
onMounted(fetchList)
watch(
  () => [pagination.current, pagination.pageSize],
  () => fetchList()
)

/** ====== 选择 / 全选 ====== */
const selectedRowKeys = ref<Key[]>([])
const rowSelection = computed<TableRowSelection<Row>>(() => ({
  selectedRowKeys: selectedRowKeys.value,
  onChange: (keys: Key[]) => (selectedRowKeys.value = keys),
}))
const currentPageKeys = computed<Key[]>(() => pageData.value.map((r) => r.id))
const checkAll = computed(() => currentPageKeys.value.length > 0 && currentPageKeys.value.every((k) => selectedRowKeys.value.includes(k)))
function onCheckAll(e: any) {
  const checked = e?.target?.checked
  if (checked) {
    const set = new Set([...selectedRowKeys.value, ...currentPageKeys.value])
    selectedRowKeys.value = Array.from(set)
  } else {
    selectedRowKeys.value = selectedRowKeys.value.filter((k) => !currentPageKeys.value.includes(k))
  }
}

/** ====== 列定义 ====== */
const columns = [
  { title: '名称', dataIndex: 'name', key: 'name', width: 220 },
  { title: '添加人', dataIndex: 'owner', key: 'owner', width: 160, sorter: false, columnKey: 'owner' },
  { title: '发布时间', dataIndex: 'publishTime', key: 'publishTime', width: 220, sorter: true, columnKey: 'publishTime' },
  { title: '状态', dataIndex: 'status', key: 'status', width: 120, sorter: false, columnKey: 'status' },
  { title: '操作', key: 'actions', width: 220 },
]

/** ====== 操作区 ====== */
function onAdd() {
  router.push({ path: '/synonymFormAdd', query: { tab: TAB_KEY, backTo: 'tab' } })
}
function onNameClick(row: Row) {
  router.push({
    path: ROUTE_INFO,
    query: {
      tab: TAB_KEY,
      backTo: 'tab',
      id: String(row.id),
      row: encodeURIComponent(JSON.stringify({
        id: row.id,
        words: String(row.name || '').replace(/｜/g, '|'),
        enabled: row.status === 'enabled',
      })),
    },
  })
}
function onEdit(row: Row) {
  router.push({
    path: ROUTE_FORM,
    query: {
      tab: TAB_KEY, mode: 'edit', id: String(row.id), backTo: 'tab',
      row: encodeURIComponent(JSON.stringify(row)),
    },
  })
}
async function onDelete(row: Row) {
  Modal.confirm({
    title: '确认删除该记录？',
    content: `将删除：${row.name || row.id}`,
    okText: '删除', okType: 'danger', cancelText: '取消',
    async onOk() {
      try {
        await deleteSynonym(row.id)
        selectedRowKeys.value = selectedRowKeys.value.filter(k => k !== row.id)
        await fetchList()
        message.success('删除成功')
      } catch (e: any) {
        message.error(e?.message || '删除失败')
      }
    },
  })
}
async function onToggleStatus(row: Row, action: 'enable' | 'disable') {
  try {
    if (action === 'enable') {
      await enableSynonym(row.id); row.status = 'enabled'; message.success('已启用')
    } else {
      await disableSynonym(row.id); row.status = 'disabled'; message.success('已停用')
    }
  } catch (e: any) { message.error(e?.message || '操作失败') }
}

/** ====== 整行点击跳转 ====== */
function onCustomRow(record: Row) {
  return {
    onClick: (e: MouseEvent) => {
      const target = e.target as HTMLElement
      if (target && target.closest('.ops')) return 
      onNameClick(record) 
    },
    style: { cursor: 'pointer' },
  } as any
}

/** ====== 批量删除 ====== */
async function onBatchDelete() {
  if (!selectedRowKeys.value.length) return
  Modal.confirm({
    title: '确认删除选中项？',
    okText: '删除', okType: 'danger', cancelText: '取消',
    async onOk() {
      try {
        await deleteSynonyms(selectedRowKeys.value as Array<string | number>)
        message.success('删除成功')
        await fetchList()
      } catch (e: any) {
        message.error(e?.message || '删除失败')
      }
    },
  })
}

/** ====== 导出 ====== */
const exporting = ref(false)
const exportVisible = ref(false)
const exportFormat = ref<'csv' | 'json'>('csv')
function onOpenExport() { exportVisible.value = true }
function onCancelExport() { exportVisible.value = false }
function triggerDownload(blob: Blob, filename: string) {
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a'); a.href = url; a.download = filename
  document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url)
}
async function onConfirmExport() {
  if (exporting.value) return
  exporting.value = true
  const key = 'synonym-exporting'
  message.loading({ content: '正在导出...', key, duration: 0 })
  try {
    const ids = selectedRowKeys.value as Array<string | number>
    const hasSelection = ids && ids.length > 0
    const { blob, filename, count } = await exportSynonyms({
      ids: hasSelection ? ids : undefined,
      keyword: keyword.value,
      excludeStatus: 'archived',
      sort: buildSortParam(),
      format: exportFormat.value,
    })
    if (!count) message.info({ content: '没有可导出的数据', key })
    else { triggerDownload(blob, filename); message.success({ content: `导出成功`, key }) }
    exportVisible.value = false
  } catch (e: any) { message.error({ content: e?.message || '导出失败', key }) }
  finally { exporting.value = false }
}

/** ========================= 导入 ========================= */
const importVisible = ref(false)
const importing = ref(false)
function onImport() { importVisible.value = true }
function closeImport() { importVisible.value = false }

/** ===== 读取/解析/构造 CSV 逻辑 ===== */
function readAsText(f: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.onload = () => resolve(String(reader.result || ''))
    reader.onerror = reject
    reader.readAsText(f, 'utf-8')
  })
}
function parseCsvToArrays(text: string): string[][] {
  const rows: string[][] = []
  let field = ''; let row: string[] = []; let inQuotes = false
  for (let i = 0; i < text.length; i++) {
    const ch = text[i]
    if (ch === '"') { if (inQuotes && text[i + 1] === '"') { field += '"'; i++ } else inQuotes = !inQuotes }
    else if (ch === ',' && !inQuotes) { row.push(field); field = '' }
    else if ((ch === '\n' || ch === '\r') && !inQuotes) { if (ch === '\r' && text[i + 1] === '\n') i++; row.push(field); rows.push(row); field = ''; row = [] }
    else { field += ch }
  }
  row.push(field); rows.push(row)
  if (rows.length && rows[0][0]) rows[0][0] = rows[0][0].replace(/^\uFEFF/, '')
  return rows.filter(r => r.some(c => String(c).trim().length > 0))
}
function normalizeStatus(raw: any): 'draft' | 'published' {
  const s = String(raw ?? '').trim().toLowerCase()
  if (['published', 'enable', 'enabled', 'true', '1', '启用', '上架'].includes(s)) return 'published'
  if (['draft', 'disable', 'disabled', 'false', '0', '停用', '下架'].includes(s)) return 'draft'
  return 'draft'
}
function normalizeQuerys(raw: any): string {
  const s = String(raw ?? '').trim()
  if (!s) return ''
  const parts = s.replace(/[，,]/g, ' ').replace(/[|｜]/g, ' ').split(/\s+/).map(x => x.trim()).filter(Boolean)
  return Array.from(new Set(parts)).join('｜')
}
function normalizeDate(raw: any): string {
  const s = String(raw ?? '').trim()
  if (!s) return new Date().toISOString()
  const d = new Date(s)
  return isNaN(d.getTime()) ? new Date().toISOString() : d.toISOString()
}
function rowsFromCSV(text: string) {
  const arr = parseCsvToArrays(text)
  if (!arr.length) throw new Error('空文件')
  const header = arr[0].map(h => String(h || '').trim().toLowerCase())
  let qi = header.indexOf('querys')
  let si = header.indexOf('status')
  let di = header.indexOf('date_created')
  if (qi < 0) qi = header.findIndex(h => ['名称', '同义词', 'name', 'queries', '词条'].includes(h))
  if (si < 0) si = header.findIndex(h => ['状态', 'status'].includes(h))
  if (di < 0) di = header.findIndex(h => ['发布时间', '创建时间', 'date', 'time', 'date_created'].includes(h))
  if (qi < 0 || si < 0) throw new Error('CSV 表头至少包含“名称/同义词”和“状态”两列')
  return arr.slice(1).map((cols, i) => {
    const line = i + 2
    const querys = normalizeQuerys(cols[qi]); if (!querys) throw new Error(`第 ${line} 行：名称 为空`)
    const status = normalizeStatus(cols[si])
    const date_created = normalizeDate(di >= 0 ? cols[di] : '')
    return { querys, status, date_created }
  })
}
function rowsFromJSON(text: string) {
  let data: any; try { data = JSON.parse(text) } catch { throw new Error('JSON 解析失败') }
  if (!Array.isArray(data)) throw new Error('JSON 顶层必须是数组')
  return data.map((it: any, idx: number) => {
    const querys = normalizeQuerys(it?.querys ?? it?.名称 ?? it?.name ?? it?.queries)
    if (!querys) throw new Error(`第 ${idx + 1} 条：名称 为空`)
    const status = normalizeStatus(it?.status ?? it?.状态)
    const date_created = normalizeDate(it?.date_created ?? it?.发布时间 ?? it?.创建时间)
    return { querys, status, date_created }
  })
}
function buildCSV(rows: Array<{ querys: string; status: string; date_created: string }>): string {
  const header = ['querys', 'status', 'date_created']
  const esc = (v: any) => { const s = String(v ?? ''); return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s }
  const lines = [header.join(','), ...rows.map(r => [r.querys, r.status, r.date_created].map(esc).join(','))]
  return '\uFEFF' + lines.join('\n')
}
async function doImport(file: File) {
  if (importing.value) return
  const ext = file.name.split('.').pop()?.toLowerCase()
  if (!['csv', 'json'].includes(ext || '')) { message.error('仅支持 .csv 或 .json'); return }
  importing.value = true
  const key = 'synonym-import'
  message.loading({ content: '正在校验并上传...', key, duration: 0 })
  try {
    const text = await readAsText(file)
    let rows: Array<{ querys: string; status: 'draft' | 'published'; date_created: string }> = []
    try { rows = ext === 'csv' ? rowsFromCSV(text) : rowsFromJSON(text) }
    catch (e: any) { throw new Error(e?.message || '文件内容不合法') }
    if (!rows.length) throw new Error('没有可导入的数据')

    const map = new Map<string, { querys: string; status: any; date_created: string }>()
    rows.forEach(r => { if (r.querys) map.set(r.querys, r) })
    const finalRows = Array.from(map.values())

    const csvText = buildCSV(finalRows)
    const blob = new Blob([csvText], { type: 'text/csv;charset=utf-8' })
    const fname = `synonyms_import_${Date.now()}.csv`
    await importSynonymsFile(blob, fname)

    message.success({ content: `导入成功`, key })
    importVisible.value = false
    fetchList()
  } catch (err: any) {
    const code =
      err?.response?.data?.errors?.[0]?.extensions?.code ||
      err?.data?.errors?.[0]?.extensions?.code ||
      err?.code
    if (code === 'RECORD_NOT_UNIQUE') {
      message.error({ content: '检测到重复的值', key })
    } else {
      message.error({ content: err?.message || '导入失败', key })
    }
  } finally { importing.value = false }
}
</script>

<style lang="less" scoped>
.table :deep(.name-link) {
  color: #1677ff;
  cursor: pointer;
  text-decoration: none;
}

/* 名称列：改为黑色文本 */
.table :deep(.name-text) {
  color: #000;
}

.table :deep(.status.on) {
  color: #1f7a1f;
}

.table :deep(.status.off) {
  color: #999;
}

.table :deep(.ops .sep) {
  margin: 0 8px;
  color: #999;
}

.table :deep(.ops .disabled) {
  color: #c5c5c5 !important;
  cursor: not-allowed;
  pointer-events: none;
}
</style>
